<?php

namespace app\models\tableModel;

use app\models\CommonModel;
use app\models\table\AdminMenu;
use yii\helpers\ArrayHelper;

/**
 * 后台菜单[Model]
 * User: Administrator
 * Date: 1995/12/22
 * Time: 17:59
 */
class AdminMenuModel extends AdminMenu
{

    /**
     * 状态 列表
     * @var array
     */
    private static $statusList = [
        'disabled' => -1,
        'open' => 1
    ];
    /**
     * 状态文本 列表文本
     * @var array
     */
    private static $statusListText = [
        -1 => '已禁用',
        1 => '已开启'
    ];
    /**
     * 是否有子集 列表
     * @var array
     */
    private static $hasChildList = [
        'has' => 1,
        'not' => 0
    ];
    /**
     * 排序最大值
     * @var int
     */
    protected static $sortMax = 9999999;
    /**
     * 排序最小值
     * @var int
     */
    protected static $sortMin = -999999;

    /**
     * 基础[SQL]
     * @var \yii\db\ActiveQuery
     */
    public $sqlBase;

    /**
     * 静态错误暂存
     * @var
     */
    public static $error_;

    /**
     * id等级列表
     * @var array
     */
    private $lvIdList = [];

    /**
     * 暂存 - 记录列表循环等级
     * @var int
     */
    private $listLv = 1;

    /**
     * 条件
     * @var
     */
    private $where;
    /**
     * 父级专用条件
     * @var array
     */
    private $parentWhere = [];
    /**
     * 子级专用条件
     * @var array
     */
    private $childWhere = [];

    /**
     * 规则验证
     * @return array
     */
    public function rules()
    {

        $parent = parent::rules();
        // 状态
        $statusList = array_values(self::getStatList());
        // 是否有下级
        $hasChildList = array_values(self::getHasChildList());

        return ArrayHelper::merge($parent, [
            ['status', 'in', 'range' => $statusList, 'message' => '状态不合法'],
            ['has_child', 'in', 'range' => $hasChildList, 'message' => '是否存在下级不合法'],
            ['parent_id', 'checkParentId'],
            ['top_id', 'checkTopId'],
        ]);
    }

    /**
     * 验证[parent_id]是否合法
     * @param null $attributeNames
     * @param bool $clearErrors
     * @return bool
     */
    public function checkParentId($attributeNames = null, $clearErrors = true)
    {

        // [0]组委父级菜单直接成功
        if ($this->$attributeNames == 0) {
            return true;
        }

        $parentItem = self::findOne([
            'id' => $this->$attributeNames
        ]);
        // 记录不存在
        if (empty($parentItem)) {
            $this->addError($attributeNames, '父级菜单不存在');
            return false;
        }
        // 记录不存在
        if ($parentItem['status'] == self::getStatDisabled()) {
            $this->addError($attributeNames, '父级菜单已禁用');
            return false;
        }

        // 赋值找到的顶部编号
        $this->top_id = $parentItem['top_id'];

        // 如果父级编号是空的 || 此次操作的父级顶级编号和查询到的编号相同
        if (empty($parentItem['parent_id']) || $this->top_id == $parentItem['parent_id']) {
            return true;
        }

        // 否则。在向上一级找到顶级
        $parentItem = self::findOne([
            'id' => $parentItem['parent_id']
        ]);

        // 顶级记录不存在
        if (empty($parentItem)) {
            $this->addError($attributeNames, '顶级菜单不存在');
            return false;
        }
        // 顶级记录不存在
        if ($parentItem['status'] == self::getStatDisabled()) {
            $this->addError($attributeNames, '顶级菜单已禁用');
            return false;
        }

        return true;
    }

    /**
     * 验证[top_id]是否合法
     * @param null $attributeNames
     * @param bool $clearErrors
     * @return bool
     */
    public function checkTopId($attributeNames = null, $clearErrors = true)
    {

        // [0]组委父级菜单直接成功
        if ($this->$attributeNames == 0) {
            return true;
        }

        $parentItem = self::findOne([
            'id' => $this->$attributeNames
        ]);
        // 记录不存在
        if (empty($parentItem)) {
            $this->addError($attributeNames, '顶级菜单不存在');
            return false;
        }
        // 记录不存在
        if ($parentItem['status'] == self::getStatDisabled()) {
            $this->addError($attributeNames, '顶级菜单已禁用');
            return false;
        }

        return true;
    }

    /**
     * 重写label的 文字
     */
    public function attributeLabels()
    {
        return [
            'id' => '编号',
            'name' => '名称',
            'status' => '状态',
        ];
    }

    /**
     * 场景
     * @return array
     */
    public function scenarios()
    {

        $scenarios = parent::scenarios();
        return ArrayHelper::merge($scenarios, [
            [
                // 自定义场景 (无用请删除)
                'scUpdate' => [
                    'someAttributes'
                ]
            ]
        ]);
    }

    /**
     * 加载整体[Model]
     * @param null $id 编号
     * @param string $scenario 场景
     * @return AdminMenuModel
     */
    public static function loadModel($id = null, $scenario = 'default')
    {

        // 实力化类
        $model = new self();

        // [id]是[true]返回
        if ($id === true) {

            $model = $model::find();
        } else if (!empty($id)) {  // 有[id]去查询

            $model = $model::findOne($id);
        }

        // // 条目不存在或者需要[find]都返回 - 无法加载场景
        if (!$model || $id === true) {
            return $model;
        }

        // 场景
        $sceList = array_keys($model->scenarios());
        if (!empty($scenario) && in_array($scenario, $sceList)) $model->setScenario($scenario);

        return $model;
    }

    /**
     * 获取全部列表
     * @param null $filed 字段
     * @param bool $idIsKey [id]是否作为键值
     * @return array
     */
    public function getList($filed = null, $idIsKey = false)
    {

        // 条件
        $where = $this->where;

        // 查找的 字段空的 就默认给列表
        if (!$filed) $filed = '*';

        // 基础[where]加载完毕
        $this->sqlBase = $this::find()
            ->select($filed)
            ->where($where);

        // 数据的获取 分页等
        $list = $this->sqlBase
            ->andWhere($this->parentWhere)
            ->andWhere([
                'parent_id' => 0
            ])->orderBy("`sort` DESC, `id` ASC")->asArray()->all();

        // 格式化数据
        foreach ($list as $k => &$v) {

            // 当前等级为 1
            $this->listLv = 1;
            // 状态文本
            if (isset($v['status'])) {
                $v['status_text'] = self::getStatusText($v['status']);
            }

            // 是否禁用
            if (isset($v['status']) && $v['status'] == self::getStatDisabled()) {
                $v['disabled'] = true;
            }

            // [id]赋值[value]
            if (isset($v['id'])) {
                $v['value'] = $v['id'];
                $v['key'] = $v['id'];
            }

            // [name]赋值[label]
            if (isset($v['name'])) {
                $v['label'] = $v['name'];
            }

            // 有子集获取子集
            if (isset($v['has_child']) && $v['has_child'] == self::getHasChildHas()) {

                // 当前等级为 1
                $this->listLv = 2;
                $v['children'] = $this->getChildList($v['id'], $idIsKey);
            }
        }

        // 编号是否作为键值
        if ($idIsKey) $list = array_column($list, null, 'id');

        return $list;
    }

    /**
     * 获取[二级菜单]全部列表
     * @param int $parentId 父级编号
     * @param bool $idIsKey [id]是否作为键值
     * @return array|\yii\db\ActiveRecord[]
     */
    public function getChildList($parentId = 0, $idIsKey = false)
    {

        if (empty($parentId)) return [];

        // 数据的获取 分页等
        $list = $this->sqlBase
            ->where($this->where)
            ->andWhere($this->childWhere)
            ->andWhere([
                'parent_id' => $parentId
            ])->orderBy("`sort` DESC, `id` ASC")->asArray()->all();

        // 格式化数据
        foreach ($list as $k => &$sv) {

            // 状态文本
            if (isset($sv['status'])) {
                $sv['status_text'] = self::getStatusText($sv['status']);
            }

            // 是否禁用
            if (isset($sv['status']) && $sv['status'] == self::getStatDisabled()) {
                $sv['disabled'] = true;
            }

            // 其他禁用 - 是否禁用
            if (isset($sv['status']) && $sv['status'] == self::getStatDisabled() || $this->listLv >= 3) {
                $sv['isDisabled'] = true;
            }

            // [id]赋值[value]
            if (isset($sv['id'])) {
                $sv['value'] = $sv['id'];
                $sv['key'] = $sv['id'];
            }

            // [name]赋值[label]
            if (isset($sv['name'])) {
                $sv['label'] = $sv['name'];
            }

            // 有子集获取子集
            if (!empty($sv['has_child']) && $sv['has_child'] == self::getHasChildHas()) {

                $this->listLv = $this->listLv + 1;
                $sv['children'] = $this->getChildList($sv['id'], $idIsKey);
                $this->listLv = $this->listLv - 1;
            }
            if (empty($sv['children'])) unset($sv['children']);
        }

        // 编号是否作为键值
        if ($idIsKey) $list = array_column($list, null, 'id');

        return $list;
    }

    /**
     * 最后一级编号获取等级编号列表
     * @param $id
     * @return array
     */
    public function lastGetLvIdList($id = false)
    {

        if (!$id) {
            return [0 => 0];
        }

        $detail = self::findOne(['id' => $id]);
        // 数据不存在返回
        if (empty($detail)) return [];

        // 父级是空的则最后一次了
        if (empty($detail['parent_id'])) return [$detail['id']];

        $parentIdList = $this->lastGetLvIdList($detail['parent_id']);

        // id是自身的话直接返回列表
        if ($id == $this->id) return $parentIdList;

        return array_merge($parentIdList, [$id]);
    }

    /**
     * 加载条件
     * @param $where
     * @return $this
     */
    public function loadWhere($where)
    {

        // 条件不存在
        if (empty($where)) {

            return $this;
        }

        // 如果[where][0]是'and' 直接赋值
        $canRetList = ['and', 'or', 'AND', 'OR'];
        if (!empty($where[0]) && in_array($where[0], $canRetList)) {

            $this->where = $where;
            return $this;
        }

        // 不是数组 字符直接 判断
        if (!is_array($where)) {

            // 条件是 有效
            if (!empty($where) && $this->hasAttribute($where))

                $this->where = $where;

            // 条件 无有效
            return $this;
        }

        // 循环  条件是否有效
        $stagingWhere = ['and'];
        foreach ($where as $k => $v) {

            // 首先值是有的，不能是空
            if ($v && is_array($v) && count($v) > 0 && $this->hasAttribute($k)) {

                $stagingWhere[] = ['IN', $k, array_values($v)];
                continue;
            }

            // 首先值是有的，不能是空
            if ($v && $this->hasAttribute($k))

                $stagingWhere[] = ['=', $k, $v];
        }

        // 条件最终赋值
        $this->where = $stagingWhere;

        return $this;
    }

    /**
     * 父级加载条件
     * @param $where
     * @return $this
     */
    public function loadParentWhere($where)
    {

        // 条件不存在
        if (empty($where)) {

            return $this;
        }

        // 如果[where][0]是'and' 直接赋值
        $canRetList = ['and', 'or', 'AND', 'OR'];
        if (!empty($where[0]) && in_array($where[0], $canRetList)) {

            $this->parentWhere = $where;
            return $this;
        }

        // 不是数组 字符直接 判断
        if (!is_array($where)) {

            // 条件是 有效
            if (!empty($where) && $this->hasAttribute($where))

                $this->parentWhere = $where;

            // 条件 无有效
            return $this;
        }

        // 循环  条件是否有效
        $stagingWhere = ['and'];
        foreach ($where as $k => $v) {

            // 首先值是有的，不能是空
            if ($v && is_array($v) && count($v) > 0 && $this->hasAttribute($k)) {

                $stagingWhere[] = ['IN', $k, array_values($v)];
                continue;
            }

            // 首先值是有的，不能是空
            if ($v && $this->hasAttribute($k))

                $stagingWhere[] = ['=', $k, $v];
        }

        // 条件最终赋值
        $this->parentWhere = $stagingWhere;

        return $this;
    }

    /**
     * 子级加载条件
     * @param $where
     * @return $this
     */
    public function loadChildWhere($where)
    {

        // 条件不存在
        if (empty($where)) {

            return $this;
        }

        // 如果[where][0]是'and' 直接赋值
        $canRetList = ['and', 'or', 'AND', 'OR'];
        if (!empty($where[0]) && in_array($where[0], $canRetList)) {

            $this->childWhere = $where;
            return $this;
        }

        // 不是数组 字符直接 判断
        if (!is_array($where)) {

            // 条件是 有效
            if (!empty($where) && $this->hasAttribute($where))

                $this->childWhere = $where;

            // 条件 无有效
            return $this;
        }

        // 循环  条件是否有效
        $stagingWhere = ['and'];
        foreach ($where as $k => $v) {

            // 首先值是有的，不能是空
            if ($v && is_array($v) && count($v) > 0 && $this->hasAttribute($k)) {

                $stagingWhere[] = ['IN', $k, array_values($v)];
                continue;
            }

            // 首先值是有的，不能是空
            if ($v && $this->hasAttribute($k))

                $stagingWhere[] = ['=', $k, $v];
        }

        // 条件最终赋值
        $this->childWhere = $stagingWhere;

        return $this;
    }

    /**
     * 获取记录总数量
     * @return int|string
     */
    public function getCount()
    {

        // 条件
        $where = $this->where;

        // 基础 where加载完毕
        $count = $this::find()->where($where)->count();

        return $count;
    }

    /**
     * 添加|保存
     * @return bool
     */
    public function saveData()
    {

        $nowTime = time();
        // 添加的话要赋值一些初始数据
        if (empty($this->id)) {

            // 可以是走mongoId
            $this->id = CommonModel::newMongoId();
            $this->add_time = $nowTime;
        }
        // 父级编号默认赋值空则为 '0'
        if (empty($this->parent_id)) {
            $this->parent_id = '0';
        }

        $this->update_time = $nowTime;

        if ($this->hasErrors() || !$this->validate() || !$this->save()) {

            return false;
        }

        return true;
    }

    /**
     * 根据[Auth权限]过滤菜单列表
     * @param array $authUrlList
     * @param bool $isSuper
     * @return array
     */
    public function filterMenuByAuth($authUrlList = [], $isSuper = false)
    {

        // 权限是空的
        if (empty($authUrlList)) return [];

        // 基础条件
        $baseWhere = [
            'AND'
        ];
        // 非超管 需查询连接
        if (!$isSuper) {
            $authUrlList[] = '#'; // 父级列表
            $baseWhere[] = ['IN', 'url', $authUrlList];
        }

        // 先获取下子集
        $parentList = self::find()
            ->select('top_id')
            ->where($baseWhere)
            ->groupBy('top_id')
            ->asArray()->all();

        // 子集是空的返回下
        if (empty($parentList)) return [];
        // [父级编号]取出列表
        $parentIdList = array_column($parentList, 'top_id');

        $authUrlList[] = '#'; // 添加一个#父级列表
        $selfModel = self::loadModel();
        $menuList = $selfModel->loadWhere(array_merge($baseWhere, [
            ['=', 'status', self::getStatOpen()] // 状态太正常的
        ]))->loadParentWhere([ // 父级的条件
            'AND',
            ['IN', 'id', $parentIdList]
        ])->getList('id, name, url, font_icon, has_child, top_id', true);

        return $menuList;
    }

    /**
     * 重新加载是否有子集
     *  ` 作用：将查询规定编号下是否有子集，也可以强制直接定义是否有或者无 `
     * @param $id
     * @param int $hasChild
     * @return bool
     */
    public static function updateHasChildren($id, $hasChild = null)
    {

        // [id]是数组直接返回否
        if (is_array($id)) return false;
        // 验证下是否有子集合法
        $hasChildList = array_values(self::getHasChildList());
        if (!in_array($hasChild, $hasChildList) || !$hasChild) {
            $childList = self::findAll(['parent_id' => $id]);
            $hasChild = !$childList ? self::getHasChildNot() : self::getHasChildHas();
        }

        return self::updateField($id, ['has_child' => $hasChild]);
    }

    /**
     * 更新[STATUS]状态操作
     * @param $id
     * @param $status
     * @return bool
     */
    public static function updateStatus($id, $status)
    {

        $db = \Yii::$app->db->createCommand();

        try {

            // 不是数组塑造下
            if (!is_array($id)) $id = explode(',', $id);

            $db->update(self::tableName(), [
                'status' => $status
            ], [
                'and',
                ['in', 'id', $id]
            ])->execute();

            // 否则成功
            return true;
        } catch (\Exception $error) {

            // 记录下错误日志
            \Yii::error([
                "````````````````````````````````````````````````````````",
                "``                      数据库错误                      ``",
                "`` 错误详情: 状态改为{$status}失败，{$error->getMessage()}  ``",
                "`` SQL语句: {$db->getRawSql()}                         ``",
                "`` 错误信息和参数详情:                                    ``",
                "````````````````````````````````````````````````````````",
                $error->getTraceAsString()
            ], 'normal');

            self::$error_ = CommonModel::renderModelError('status', $error->getMessage());
            return false;
        }
    }

    /**
     * 更新某些字段
     * @param $id
     * @param array $fieldVal
     * @return bool
     */
    public static function updateField($id, $fieldVal = [])
    {

        $model = new self();
        foreach ($fieldVal as $k => $v) {

            if (!$model->hasAttribute($k)) {

                unset($fieldVal[$k]);
                continue;
            }
        }

        $db = \Yii::$app->db->createCommand();

        try {

            // 不是数组塑造下
            if (!is_array($id))
                $id = explode(',', $id);

            $db->update(self::tableName(), $fieldVal, [
                'and',
                ['IN', 'id', $id]
            ])->execute();

            // 否则成功
            return true;
        } catch (\Exception $error) {

            // 记录下错误日志
            \Yii::error([

                "````````````````````````````````````````````````````````",
                "``                      数据库错误                      ``",
                "`` 错误详情: 修改[指定字段]失败，{$error->getMessage()}      ``",
                "`` SQL语句: {$db->getRawSql()}                         ``",
                "`` 错误信息和参数详情:                                    ``",
                "````````````````````````````````````````````````````````",
                $error->getTraceAsString()
            ], 'normal');

            self::$error_ = empty($error->errorInfo) ?
                $error->getMessage() :
                implode(' | ', $error->errorInfo);

            return false;
        }
    }


    /**
     * 返回排序最大值
     * @return int
     */
    public static function getSortMax()
    {
        return self::$sortMax;
    }

    /**
     * 返回排序最小值
     * @return int
     */
    public static function getSortMin()
    {
        return self::$sortMin;
    }

    /**
     * 获取[正常]状态 值
     * @return mixed|string
     */
    public static function getStatOpen()
    {

        // 最终正常返回
        return self::$statusList['open'];
    }

    /**
     * 获取[禁用]状态 值
     * @return mixed|string
     */
    public static function getStatDisabled()
    {

        // 最终正常返回
        return self::$statusList['disabled'];
    }

    /**
     * 获取[状态]列表 值
     * @return mixed|string
     */
    public static function getStatList()
    {

        // 最终正常返回
        return self::$statusList;
    }

    /**
     * 获取[状态]文本
     * @param $value
     * @return mixed|string
     */
    public static function getStatusText($value)
    {

        // 列表
        $list = self::$statusListText;
        // 不合法 - 不存在
        if (empty($list[$value]))

            return '--';

        // 最终正常返回
        return $list[$value];
    }

    /**
     * 获取[是否有子集]有 值
     * @return mixed
     */
    public static function getHasChildHas()
    {

        // 最终正常返回
        return self::$hasChildList['has'];
    }

    /**
     * 获取[是否有子集]无 值
     * @return mixed
     */
    public static function getHasChildNot()
    {

        // 最终正常返回
        return self::$hasChildList['not'];
    }

    /**
     * 获取[是否有子集]列表 值
     * @return array
     */
    public static function getHasChildList()
    {
        // 最终正常返回
        return self::$hasChildList;
    }
}
